#include <winsock2.h>
#include <io.h>
#include <tchar.h>
#include <stdio.h>
#include <stdlib.h>
#include <time.h>

// UELogger Support
#include "litelog.h"
extern "C" int logfd = 0;

#include "libue.h"
#include "uecgi.h"

int main(int argc, char** argv)
{
	int ret = 0;
	char buf[MAX_BUF_LEN];
	int s = 0;
	memset(buf, 0, MAX_BUF_LEN);
	time_t systime = 0;

	/* get current time stamp */
	time(&systime);

	/* initialize debug log */
	logfd = InitCGILogFile(NULL);
#if defined(_DEBUG) || defined(DEBUG)
	loglevel = DEBUG_LOG_LEVEL_INFO;
#endif

	/* initialize windows socket */
	dbglog("Initialize windows socket", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);
	if (!InitWinSock2())
	{
		dbglog("Initialize windows socket failed.", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__);
		printf("\r\n");
		printf("{\"status\": -2, \"description\": \"System Error - Initialize windows socket failed!\"}");

		if (logfd > 0)
			_close(logfd);

		return -2;
	}

	CUECGIDatabase uecgidb;

	/* get http request body (the password) */
	char *str_len = NULL;
	size_t len;

	dbglog("Get HTTP request body length.", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);
	int err = _dupenv_s(&str_len, &len, "CONTENT_LENGTH");
	if (err)
	{
		dbglog("Get CONTENT_LENGTH environment variable failed.", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__);
		printf("\r\n");
		printf("{\"status\": -1, \"description\": \"System Error - Get CONTENT_LENGTH environment variable failed!\"}");
		ret = -1;
		goto Exit;
	}

	if (str_len == NULL)
	{
		dbglog("Content Length Unknown.", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__);
		printf("{\"status\": 1, \"description\": \"Invalid Request - Content Length Unknown!\"}");
		ret = 1;
		goto Exit;
	}

	len = atoi(str_len);
	free(str_len);
	if (len == 0 || len >= MAX_BUF_LEN)
	{
		dbglogex("Invalid Conetent Length: %d", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, len);
		printf("\r\n");
		printf("{\"status\": 2, \"description\": \"Invalid Request - Content Length Invalid!\"}");
		ret = -2;
		goto Exit;
	}

	dbglogex("HTTP request body length: %d", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, len);
	fread(buf, 1, len, stdin);
	int parameter_len = strlen(PARAMETER_PASSWORD_NAME);
	if (strncmp(PARAMETER_PASSWORD_NAME, buf, parameter_len) || buf[parameter_len] != '=')
	{
		dbglog("Invalid Parameter Format", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__);
		printf("\r\n");
		printf("{\"status\": 3, \"description\": \"Invalid Request - Parameter Format Incorrect!\"}");
		ret = 3;
		goto Exit;
	}

	char *password = buf + parameter_len + 1;
	dbglogex("Read password success: %s", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, password);

	/* connect to UE server and authenticate the password */
	err = ue_connect(GetUEServerAddress(), GetUEServerPort(), &s);
	if (err)
	{
		dbglogex("Connect to UE server failed with return value: %d", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, err);
		printf("\r\n");
		printf("{\"status\": 4, \"description\": \"Connect to back-end server failed!\"}");
		ret = 4;
		goto Exit;
	}
	dbglog("Connect to UE server success", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

	err = ue_authenticate(s, password);
	if (err)
	{
		dbglogex("Authenticate failed with return value: %d", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, err);
		printf("\r\n");
		printf("{\"status\": 5, \"description\": \"Authenticate failed!\"}");
		ret = 5;
		goto Exit;
	}
	
	dbglog("Authenticate success", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);
	/* TODO: generate session id and CSRF token */
	char session_id[] = "1234567890";
	srand((unsigned int)systime);
	unsigned int token = rand();
	token = rand();
	
	/* connect to database and store the relation ship between session_id, CSRF token and password */
	if (!uecgidb.Connect())
	{
		dbglog("Connect to CGI database failed.", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__);
		printf("\r\n");
		printf("{\"status\": 6, \"description\": \"Connect to database failed!\"}");
		ret = 6;
		goto Exit;
	} /* connect to database failed */
	dbglog("Connect to database success", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

	char SQL[MAX_SQL_LEN];
	sprintf_s(SQL, MAX_SQL_LEN, "insert into sessions values(%d, '%s', %d, '%s', %d)", (int)systime, session_id, token, password, (int)systime);
	if (!uecgidb.Execute(SQL))
	{
		dbglogex("Execute SQL statement failed: %s", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, SQL);
		printf("\r\n");
		printf("{\"status\": 7, \"description\": \"Backend database error!\"}");
		ret = 7;
		goto Exit;
	} /* store data failed */
	dbglog("Store data success", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

	uecgidb.Close();

	printf("Set-cookie: sessionid=%s;http-only\r\n", session_id);
	printf("\r\n");
	printf("{\"status\": 0, \"description\": \"Authenticate success!\", \"token\": %d}", token);
	
Exit:
	if (s > 0)
		closesocket(s);

	WSACleanup();

	if (logfd > 0)
	{
		_close(logfd);
		logfd = 0;
	}

	return ret;
}